package wpmp.security.client.internal;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import wcommons.httputils.HttpUtils;
import wcommons.httputils.quickbean.RespInfo;
import wcommons.lang.UrlUtils;
import wpmp.security.client.SecurityConfig;
import wpmp.security.client.filter.StatusCode;
import wpmp.utils.Statics;
import wpmp.utils.quickbean.NeedNotLoginPermission;
import wpmp.utils.quickbean.UserPermission;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;

/**
 * @author Wayne.Wang<5waynewang@gmail.com>
 * @since 11:51:23 AM Dec 4, 2013
 */
public class PmpResourceUtils {

	private static final Log log = LogFactory.getLog(PmpResourceUtils.class);

	private static String GET_NEED_NOT_LOGIN_PERMISSION = "resource.do?action=getNeedNotLoginPermission";
	private static String GET_USER_PERMISSION = "resource.do?action=getUserPermission";
	private static String CHECK_LOGIN = "user.do?action=check";

	public static void init() {

	}

	static String getAction(HttpServletRequest req, Map<String, String> params, String actionName) {
		String action = req.getParameter(actionName);
		if (StringUtils.isBlank(action)) {
			action = params.get(actionName);
		}
		if (StringUtils.isBlank(action)) {
			action = Statics.DEFAULT_ACTION;
		}
		return action;
	}

	static boolean isNeedNotLogin(HttpServletRequest req, String url) {
		final String[] urls = UrlUtils.splitUrlParams(url);

		final Map<String, String> params = UrlUtils.getStringParamMap(urls[1]);

		final NeedNotLoginPermission needNotLoginPermission = getAndSetNeedNotLoginPermission(req);
		if (needNotLoginPermission != null) {
			// 是否不要登录可访问
			for (NeedNotLoginPermission.Entry entry : needNotLoginPermission.getResources()) {
				if (StringUtils.equals(entry.getBaseUrl(), urls[0])) {
					final String currentAction = getAction(req, params, entry.getActionName());
					final String[] actions = entry.getOperations().split(",");
					for (String action : actions) {
						if (StringUtils.equals(Statics.MATCH_ALL, action) || currentAction.startsWith(action)) {
							return true;
						}
					}
				}
			}
		}
		return false;
	}

	static boolean isLogin(String securityId) {
		final Map<String, Object> params = new HashMap<String, Object>();
		params.put("securityId", securityId);

		String result = null;

		try {
			result = HttpUtils.postForString(SecurityConfig.getAuthUrl(CHECK_LOGIN), params);
		}
		catch (Exception e) {
			log.error("Error to check Login by [" + securityId + "] from RemoteServer", e);
			return false;
		}

		if (StringUtils.isBlank(result)) {
			log.error("can not get anything from RemoteServer for check Login by [" + securityId + "]");
			return false;
		}
		final RespInfo<Object> respInfo = JSON.parseObject(result, new TypeReference<RespInfo<Object>>() {
		});
		return respInfo.isSuccess();
	}

	/**
	 * <pre>
	 * </pre>
	 * @see #checkPermission(HttpServletRequest, HttpServletResponse, String)
	 * @param req
	 * @param resp
	 * @return
	 */
	public static int checkPermission(HttpServletRequest req, HttpServletResponse resp) {
		return checkPermission(req, resp, req.getRequestURL().toString());
	}

	/**
	 * <pre>
	 * </pre>
	 * @param req
	 * @param resp
	 * @param url
	 * @return
	 */
	public static int checkPermission(HttpServletRequest req, HttpServletResponse resp, String url) {
		// 是否公共资源
		if (isNeedNotLogin(req, url)) {
			return StatusCode.SUCCESS;
		}

		final String securityId = SecurityUtils.getAndSetSecurityId(req, resp);

		if (StringUtils.isBlank(securityId)) {
			return StatusCode.NOT_LOGIN;
		}

		// 服务端判断是否已经登录
		if (!isLogin(securityId)) {
			// 无效的sid, 删除
			SecurityUtils.clearSecurityId(req, resp);
			return StatusCode.NOT_LOGIN;
		}

		final UserPermission userPermission = getAndSetUserPermission(req, securityId);
		if (userPermission == null) {
			return StatusCode.NOT_LOGIN;
		}

		// 管理员直接OK
		if (userPermission.getUser().isAdmin()) {
			return StatusCode.SUCCESS;
		}

		final String[] urls = UrlUtils.splitUrlParams(url);

		final Map<String, String> params = UrlUtils.getStringParamMap(urls[1]);

		for (UserPermission.Entry entry : userPermission.getResources()) {
			if (StringUtils.equals(entry.getBaseUrl(), urls[0])) {
				final String currentAction = getAction(req, params, entry.getActionName());
				final String[] actions = entry.getOperations().split(",");
				for (String action : actions) {
					if (StringUtils.equals(Statics.MATCH_ALL, action) || currentAction.startsWith(action)) {
						return StatusCode.SUCCESS;
					}
				}
			}
		}

		return StatusCode.NO_PERMISSION;
	}

	static String getNeedNotLoginPermissionKey() {
		return "NeedNotLoginPermission_";
	}

	static NeedNotLoginPermission getRemoteNeedNotLoginPermission() {
		final String result = HttpUtils.getForString(SecurityConfig.getAuthUrl(GET_NEED_NOT_LOGIN_PERMISSION));
		if (StringUtils.isBlank(result)) {
			log.error("can not find NeedNotLoginPermission from RemoteServer");
			return null;
		}
		final RespInfo<NeedNotLoginPermission> respInfo = JSON.parseObject(result,
				new TypeReference<RespInfo<NeedNotLoginPermission>>() {
				});
		if (respInfo.isSuccess()) {
			return respInfo.getResult();

		}
		log.error("Failed to get NeedNotLoginPermission from RemoteServer, response: " + result);
		return null;
	}

	/**
	 * <pre>
	 * </pre>
	 * @param req
	 * @return
	 */
	public static NeedNotLoginPermission getAndSetNeedNotLoginPermission(HttpServletRequest req) {
		final String key = getNeedNotLoginPermissionKey();
		NeedNotLoginPermission needNotLoginPermission = (NeedNotLoginPermission) req.getSession().getAttribute(key);
		if (needNotLoginPermission != null) {
			return needNotLoginPermission;
		}

		try {
			needNotLoginPermission = getRemoteNeedNotLoginPermission();
			// 放入session
			req.getSession().setAttribute(key, needNotLoginPermission);
		}
		catch (Exception e) {
			log.error("Error to get NeedNotLoginPermission from RemoteServer", e);
		}

		return needNotLoginPermission;
	}

	/**
	 * <pre>
	 * </pre>
	 * @param req
	 * @return
	 */
	public static UserPermission getAndSetUserPermission(HttpServletRequest req) {
		final String securityId = SecurityUtils.getSecurityId(req);
		if (StringUtils.isBlank(securityId)) {
			return null;
		}
		return getAndSetUserPermission(req, securityId);
	}

	static String getUserPermissionKey(String securityId) {
		return Statics.USER_PERMISSION + securityId;
	}

	static UserPermission getRemoteUserPermission(String securityId) {
		final Map<String, Object> params = new HashMap<String, Object>();
		params.put("securityId", securityId);

		final String result = HttpUtils.getForString(SecurityConfig.getAuthUrl(GET_USER_PERMISSION), params);
		if (StringUtils.isBlank(result)) {
			log.error("can not find UserPermission by [" + securityId + "] from RemoteServer");
			return null;
		}

		final RespInfo<UserPermission> respInfo = JSON.parseObject(result,
				new TypeReference<RespInfo<UserPermission>>() {
				});
		if (respInfo.isSuccess()) {
			return respInfo.getResult();
		}

		log.error("Failed to get UserPermission by securityId[" + securityId + "] from RemoteServer , response: "
				+ result);
		return null;
	}

	/**
	 * <pre>
	 * </pre>
	 * @param req
	 * @param securityId
	 * @return
	 */
	public static UserPermission getAndSetUserPermission(HttpServletRequest req, String securityId) {
		if (StringUtils.isBlank(securityId)) {
			log.error("can not find securityId, please check User login");
			return null;
		}
		final String key = getUserPermissionKey(securityId);
		UserPermission userPermission = (UserPermission) req.getSession().getAttribute(key);
		if (userPermission != null) {
			return userPermission;
		}

		try {
			userPermission = getRemoteUserPermission(securityId);

			// 放入session
			req.getSession().setAttribute(key, userPermission);
		}
		catch (Exception e) {
			log.error("Error to get UserPermission by [" + securityId + "] from RemoteServer", e);
		}

		return userPermission;
	}
}
